#include "notepad.h"
#include "ui_notepad.h"

#include <QLabel>
#include <QMessageBox>
#include <QTextEdit>
#include <QPushButton>
#include <QLineEdit>
#include <QFontDialog>
#include <QDebug>
#include <QFileDialog>
#include <QKeySequence>
#include <QFileInfo>
#include <QDesktopServices>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>


Notepad::Notepad(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Notepad)
{
    ui->setupUi(this);
    this->setWindowIcon(QIcon(":/icons/note-1.png"));
    this->resize(1000, 600);

    // 文本框默认字体
    this->getFontInfo();
    this->ui->textEdit->setFont(QFont(this->family, this->size));

    // 1. 文件菜单
    // 另存为
    // ①在槽函数中打开文件保存框，当用户设置完文件名之后，得到文件的绝对路径
    // ②以只写方式打开文件
    // ③得到textEdit中的内容，写入文件
    ui->actionSaveAs->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_S));  // 设置快捷键
    connect(ui->actionSaveAs, &QAction::triggered, [this](){
        this->filePath = QFileDialog::getSaveFileName(this, "另存为", ".", "*.txt");
        if(!this->filePath.isEmpty())
        {
            this->writeFile();
        }
    });

    // 保存
    // ①检测filePath属性是否为空
    // ②为空说明尚未进行过任何保存操作，需要弹出文件保存框，得到文件的绝对路径，再写文件（与另存为流程一致）
    // ③不为空说明已经有了对应的文件，向文件中直接写即可
    ui->actionSave->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
    connect(ui->actionSave, &QAction::triggered, [this](){
        if(this->filePath.isEmpty())
        {
            // 为空，执行另存为流程
            this->filePath = QFileDialog::getSaveFileName(this, "另存为", ".", "*.txt");
            if(this->filePath.isEmpty())
            {
                return ;
            }
        }
        this->writeFile();

    });

    // 打开
    ui->actionOpen->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O));
    // &QTextEdit::textChanged : 每当textEdit中的内容发生改变时触发
    connect(ui->textEdit, &QTextEdit::textChanged, [this](){
        this->isSave = true;
    });
    // ①判断是否需要保存
    // ②如果需要：弹出消息框，提示用户是否需要进行保存
    //           点击"保存"：先执行"保存"菜单项功能，再执行"不需要"功能
    //           点击"不保存"：同"不需要"
    //           点击"取消"：什么都不干
    // ③不需要：打开文件选择框，当用户选中文件之后，得到文件的绝对路径，读取文件中的内容，写入 textEdit 即可
    connect(ui->actionOpen, &QAction::triggered, [this](){
        if(this->isSave)
        {
            // 需要保存
            QMessageBox tipBox(
                        QMessageBox::Information,  // 提示框的图标
                        "Notepad",
                        "要保存当前的文件吗?",
                        QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel
                        );
            tipBox.setButtonText(QMessageBox::Yes, "保存");
            tipBox.setButtonText(QMessageBox::No, "不保存");
            tipBox.setButtonText(QMessageBox::Cancel, "取消");

            int result = tipBox.exec();

            // 判断点击的按钮，进行不同的操作
            if(result == QMessageBox::Cancel)
            {
                return ;
            }
            else if(result == QMessageBox::Yes)
            {
                // 进行保存 --> 保存流程
                if(this->filePath.isEmpty())
                {
                    // 为空，执行另存为流程
                    this->filePath = QFileDialog::getSaveFileName(this, "另存为", ".", "*.txt");
                    if(this->filePath.isEmpty())
                    {
                        return ;
                    }
                }
                this->writeFile();
                // 文件修改完毕之后，一定修改 isSave的值
                this->isSave = false;
                // 调用打开文件的方法
            }
        }
        this->openFile();
    });

    // 新建
    // ①在新建菜单项上设置信号和槽
    // ②判断是否需要保存
    //   需要：设置消息框来提醒是否需要保存
    //        保存：先执行"保存:流程，再执行"不需要"流程
    //        不保存：执行"不需要"流程
    //        取消：什么都不干
    //   不需要：
    //        清空操作：清空textEdit、filePath、isSave = false
    ui->actionNew->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N));
    connect(ui->actionNew, &QAction::triggered, [this]() {
        if (this->isSave)
        {
            QMessageBox tipBox(
                QMessageBox::Question,
                "Notepad",
                "要保存当前的文件吗?",
                QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);

            tipBox.setButtonText(QMessageBox::Yes, "保存");
            tipBox.setButtonText(QMessageBox::No, "不保存");
            tipBox.setButtonText(QMessageBox::Cancel, "取消");

            int result = tipBox.exec();

            if (result == QMessageBox::Yes)
            {
                if (this->filePath.isEmpty())
                {
                    this->filePath = QFileDialog::getSaveFileName(this, "另存为", ".", "*.txt");
                    if (this->filePath.isEmpty())
                    {
                        return;
                    }
                }
                this->writeFile();
                this->isSave = false;
            }
            else if (result == QMessageBox::Cancel)
            {
                return;
            }
        }

        this->ui->textEdit->clear();
        this->filePath.clear();
        this->isSave = false;

        this->setWindowTitle("Notepad");
    });

    // 关闭
    connect(ui->actionExit, &QAction::triggered, [this](){
        QMessageBox myBox(QMessageBox::Warning,
                            "关闭",
                            "您确定要退出此应用吗？",
                            QMessageBox::Yes | QMessageBox::No
                            );

        myBox.setButtonText(QMessageBox::Yes, "是");
        myBox.setButtonText(QMessageBox::No, "否");

        int result = myBox.exec();
        if(result == QMessageBox::Yes)
        {
            this->close();
        }
    });

    // 2.编辑菜单
    ui->actionCopy->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
    ui->actionPaste->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_V));
    ui->actionCut->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X));
    ui->actionUndo->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Z));
    connect(ui->actionCopy, &QAction::triggered, ui->textEdit, &QTextEdit::copy);
    connect(ui->actionPaste, &QAction::triggered, ui->textEdit, &QTextEdit::paste);
    connect(ui->actionCut, &QAction::triggered, ui->textEdit, &QTextEdit::cut);
    connect(ui->actionUndo, &QAction::triggered, ui->textEdit, &QTextEdit::undo);

    // 3.格式菜单
    connect(ui->actionWrap, &QAction::triggered, [this](){
        this->isWrap = !this->isWrap;

        if(this->isWrap)
        {
            // 自动换行
            ui->textEdit->setLineWrapMode(QTextEdit::WidgetWidth);
            ui->actionWrap->setIcon(QIcon(":/icons/r.png"));
        }
        else
        {
            // 不自动换行
            ui->textEdit->setLineWrapMode(QTextEdit::NoWrap);
            ui->actionWrap->setIcon(QIcon());
        }
    });

    // 字体设置
    connect(ui->actionFont, &QAction::triggered, [this](){
        bool flag;
        QFont result = QFontDialog::getFont(&flag);
        // 选中字体之后，优先要更新头文件中定义的相关变量的数据
        this->family = result.family();
        this->size = result.pointSize();
        this->weight = result.weight();
        this->italic = result.italic();

        ui->textEdit->setFontFamily(result.family());
        ui->textEdit->setFontPointSize(result.pointSize());
        ui->textEdit->setFontWeight(result.weight());
        ui->textEdit->setFontItalic(result.italic());
        this->setFontInfo();
    });

    // 4.查看
    // 缩放
    // 放大
    connect(ui->actionZoomUp, &QAction::triggered, [this](){
        this->size += 2;
        ui->textEdit->setFontPointSize(this->size);
        this->setFontInfo();
    });

    // 缩小
    connect(ui->actionZoomDown, &QAction::triggered, [this](){
        this->size -= 2;
        ui->textEdit->setFontPointSize(this->size);
        this->setFontInfo();
    });

    // 设置状态栏
    connect(ui->actionStatus, &QAction::triggered, [this](){
        if(ui->actionStatus->icon().isNull())  // 状态栏图标为空
        {
            // 设置状态栏图标并显示状态栏
            ui->actionStatus->setIcon(QIcon(":/icons/r.png"));
            this->statusBar()->show();
        }
        else
        {
            // 设置状态栏图标为空并隐藏状态栏
            ui->actionStatus->setIcon(QIcon());
            this->statusBar()->hide();
        }
    });

    // 光标位置
    QLabel* cursorPositionLabel = new QLabel("行: 1 列: 1");
    ui->statusBar->addWidget(cursorPositionLabel);

    connect(ui->textEdit, &QTextEdit::cursorPositionChanged, [this, cursorPositionLabel]() {
        QTextCursor cursor = ui->textEdit->textCursor();
        int line = cursor.blockNumber() + 1;  // 行号是从0开始的，所以加1
        int column = cursor.columnNumber() + 1;  // 列号也是从0开始的，所以加1
        cursorPositionLabel->setText(QString("行: %1 列: %2").arg(line).arg(column));
    });

    // 统计字符数量
    QLabel* textSize = new QLabel("0个字符");
    ui->statusBar->addWidget(textSize);
    connect(ui->textEdit, &QTextEdit::textChanged, [textSize, this](){
        int textLength = ui->textEdit->toPlainText().trimmed().length();
        textSize->setText(QString::number(textLength) + "个字符");
    });

    // 右侧状态栏内容
    QLabel* right3 = new QLabel("100%");
    ui->statusBar->addPermanentWidget(right3);

    QLabel* right2 = new QLabel("Windows(CRLF)");
    ui->statusBar->addPermanentWidget(right2);

    QLabel* unicode = new QLabel("UTF-8");
    ui->statusBar->addPermanentWidget(unicode);

    // 5.帮助菜单
    // 关于我们
    connect(ui->actionAbout, &QAction::triggered, [this](){
        QDialog dia;
        dia.resize(600, 400);
        dia.setWindowTitle("关于我们");

        // 左侧图标
        QLabel* pic = new QLabel(this);
        pic->resize(190, 190);
        pic->move(10, 80);
        pic->setPixmap(QPixmap(":/icons/dog.gif"));
        pic->setScaledContents(true);
        pic->setParent(&dia);

        // 右侧文本内容
        QLabel* titleLabel = new QLabel("Windows 记事本 11.2406.9.0", &dia);
        titleLabel->setFont(QFont("Times New Roman", 10, true, false));
        titleLabel->resize(380, 20);
        titleLabel->move(200, 20);

        QLabel* textLabel = new QLabel;
        textLabel->setText(
                      "Based on Qt 5.12.2 (MSVC 2017， 32bit)<br><br>"
                      "Built On Apr 11 2019 21:12:37<br><br>"
                      "From revision 7885bc899f<br><br>"
                      "Copyright 2008-2019 The Qt Company Ltd. All rights reserved.<br><br>"
                      "The Program is provided AS IS with NO WARRANTY OF ANY KIND,"
                      "INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.");
        textLabel->setParent(&dia);
        textLabel->setWordWrap(true); // 允许文本内容自动换行
        textLabel->resize(380, 290);
        textLabel->move(200, 40);

        // close按钮
        QPushButton* closeBtn = new QPushButton("close", &dia);
        closeBtn->resize(160, 30);
        closeBtn->move(420, 335);
        connect(closeBtn, &QPushButton::clicked, &dia, &QDialog::close);

        dia.exec();
    });

    // 在线文档
    connect(ui->actionDoc, &QAction::triggered, [](){
        QDesktopServices::openUrl(QUrl("www.baidu.com"));
    });
}

void Notepad::openFile()
{
    this->filePath = QFileDialog::getOpenFileName(this, "打开", ".", "*.txt");
    if(!this->filePath.isEmpty())
    {
        // 当用户选中文件之后，读取文件内容，写入textEdit中
        QFile file(this->filePath);
        file.open(QIODevice::ReadOnly);
        QByteArray buf = file.readAll();
        ui->textEdit->setText(buf);
        this->setTitleStr();

        // 将isSave的状态重置为不用保存的状态
        this->isSave = false;
    }
}

void Notepad::setTitleStr()
{
    // 将文件名设置到标题栏
    QFileInfo info(this->filePath);
    this->setWindowTitle(info.fileName() + "- notepad");
}

void Notepad::writeFile()
{
    QFile file(this->filePath);
    file.open(QIODevice::WriteOnly);
    QString buf = ui->textEdit->toPlainText();
    file.write(buf.toUtf8());
    file.close();
    this->setTitleStr();
}

void Notepad::getFontInfo()
{
    QFile file("./config/font.json");
    file.open(QIODevice::ReadOnly);
    QByteArray jsonStr = file.readAll();
    QJsonObject fontObj = QJsonDocument::fromJson(jsonStr).object();
    this->family = fontObj.value("family").toString();
    this->size = fontObj.value("size").toInt();
    this->italic = fontObj.value("italic").toBool();
    this->weight = fontObj.value("weight").toInt();
}

void Notepad::setFontInfo()
{
    QJsonObject fontObj;
    fontObj.insert("family", this->family);
    fontObj.insert("size", this->size);
    fontObj.insert("italic", this->italic);
    fontObj.insert("weight", this->weight);
    QJsonDocument jsonDoc(fontObj);

    QByteArray jsonStr = jsonDoc.toJson();

    QFile file("./config/font.json");
    file.open(QIODevice::WriteOnly);
    file.write(jsonStr);
    file.close();

}

Notepad::~Notepad()
{
    delete ui;
}
